home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / telecomm / sticpsrc.lzh / SOURCE.ARC / AX25.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-10-06  |  14.1 KB  |  480 lines

  1. /* Low level AX.25 frame processing - address header */
  2.  
  3. #include <stdio.h>
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "iface.h"
  7. #include "timer.h"
  8. #include "arp.h"
  9. #include "slip.h"
  10. #include "ax25.h"
  11. #include "lapb.h"
  12. #include <ctype.h>
  13.  
  14. char axbdcst[AXALEN];    /* Broadcast address (QST-0), network format */
  15. int digipeat = 1;    /* Controls single-band standard digipeating */
  16. struct mbuf *axloopq = NULLBUF; /* Loopback queue for AX.25 packets */
  17.  
  18. /* Send IP datagrams across an AX.25 link */
  19. int
  20. ax_send(bp,interface,gateway,precedence,delay,throughput,reliability)
  21. struct mbuf *bp;
  22. struct interface *interface;
  23. int32 gateway;
  24. char precedence;
  25. char delay;
  26. char throughput;
  27. char reliability;
  28. {
  29.     char *hw_addr,*res_arp();
  30.     struct ax25_cb *axp,*find_ax25(),*open_ax25();
  31.     struct ax25 addr;
  32.     struct ax25_addr destaddr;
  33.     struct mbuf *tbp;
  34.     extern int16 axwindow;
  35.     void ax_incom();
  36.     int16 size,bsize,seq;
  37.  
  38.     if((hw_addr = res_arp(interface,ARP_AX25,gateway,bp)) == NULLCHAR)
  39.         return 0;    /* Wait for address resolution */
  40.  
  41.     if(delay || (!reliability && !(interface->flags & IF_CONNECT_MODE))){
  42.         /* Use UI frame */
  43.         return (*interface->output)(interface,hw_addr,
  44.             interface->hwaddr,PID_FIRST|PID_LAST|PID_IP,bp);
  45.     }
  46.     /* Reliability is needed; use I-frames in AX.25 connection */
  47.     memcpy(destaddr.call,hw_addr,ALEN);
  48.     destaddr.ssid = hw_addr[ALEN];
  49.  
  50.     if((axp = find_ax25(&destaddr,(struct ax25_addr *)interface->hwaddr)) == NULLAX25 ||
  51.         (axp->state != CONNECTED && axp->state != SETUP)){
  52.         /* Open a new connection or reinitialize the old one */
  53.         atohax25(&addr,hw_addr,(struct ax25_addr *)interface->hwaddr);
  54.         axp = open_ax25(&addr,axwindow,ax_incom,NULLVFP,NULLVFP,interface,(char *)0);
  55.         if(axp == NULLAX25){
  56.             free_p(bp);
  57.             return -1;
  58.         }
  59.     }
  60.     /* If datagram is too big for one frame, send all but the last with
  61.      * the extension PID. Note: the copy to a new buf is necessary because
  62.      * AX.25 may continue retransmitting the frame after a local TCB has
  63.      * gone away, and using the buf directly would cause heap garbage to be
  64.      * transmitted. Besides, nobody would ever use AX.25 anywhere
  65.      * high performance is needed anyway...
  66.      */
  67.     bsize = len_mbuf(bp);
  68.     seq = 0;
  69.     while(bsize != 0){
  70.         size = min(bsize,axp->paclen);
  71.         /* Allocate buffer, allowing space for PID */
  72.         if((tbp = alloc_mbuf(size + 1)) == NULLBUF)
  73.             break;        /* out of memory! */
  74.         *tbp->data = PID_IP;
  75.         if(seq++ == 0)
  76.             *tbp->data |= PID_FIRST;    /* First in sequence */
  77.         if(size == bsize)
  78.             *tbp->data |= PID_LAST;        /* That's all of it */
  79.         /* else more to follow */
  80.  
  81.         tbp->cnt = 1;
  82.         tbp->cnt += pullup(&bp,tbp->data + 1,size);
  83.         send_ax25(axp,tbp);
  84.         bsize -= size;
  85.     }
  86.     free_p(bp);    /* Shouldn't be necessary */
  87.     return 0;
  88. }
  89. /* Add AX.25 link header and send packet.
  90.  * Note that the calling order here must match ec_output
  91.  * since ARP also uses it.
  92.  */
  93. ax_output(interface,dest,source,pid,data)
  94. struct interface *interface;
  95. char *dest;        /* Destination AX.25 address (7 bytes, shifted) */
  96.             /* Also includes digipeater string */
  97. char *source;        /* Source AX.25 address (7 bytes, shifted) */
  98. char pid;        /* Protocol ID */
  99. struct mbuf *data;    /* Data field (follows PID) */
  100. {
  101.     struct mbuf *abp,*cbp,*htonax25();
  102.     struct ax25 addr;
  103.  
  104.     /* Allocate mbuf for control and PID fields, and fill in */
  105.     if((cbp = pushdown(data,2)) == NULLBUF){
  106.         free_p(data);
  107.         return -1;
  108.     }
  109.     cbp->data[0] = UI;
  110.     cbp->data[1] = pid;
  111.  
  112.     atohax25(&addr,dest,(struct ax25_addr *)source);
  113.     if((abp = htonax25(&addr,cbp)) == NULLBUF){
  114.         free_p(cbp);    /* Also frees data */
  115.         return -1;
  116.     }
  117.     /* This shouldn't be necessary because redirection has already been
  118.      * done at the IP router layer, but just to be safe...
  119.      */
  120.     if(interface->forw != NULLIF)
  121.         return (*interface->forw->raw)(interface->forw,abp);
  122.     else
  123.         return (*interface->raw)(interface,abp);
  124. }
  125. /* Process incoming AX.25 packets.
  126.  * After optional tracing, the address field is examined. If it is
  127.  * directed to us as a digipeater, repeat it.  If it is addressed to
  128.  * us or to QST-0 or NODES-0, kick it upstairs depending on the protocol ID.
  129.  */
  130. int
  131. ax_recv(interface,bp)
  132. struct interface *interface;
  133. struct mbuf *bp;
  134. {
  135.     void arp_input();
  136.     int ip_route();
  137.     struct ax25_addr addr,*ap;
  138.     struct mbuf *htonax25(),*hbp;
  139.     struct ax25 hdr;
  140.     register struct ax25_cb *axp;
  141.     struct ax25_cb *find_ax25(),*cr_ax25();
  142.     register struct ax25_call *axc;
  143.     struct ax25_call *axd;
  144.     int timerscale,setdigi;
  145.     extern int16 t1init,t2init,t3init,t4init;
  146.  
  147.     /* Pull header off packet and convert to host structure */
  148.     if(ntohax25(&hdr,&bp) < 0){
  149.         /* Something wrong with the header */
  150.         free_p(bp);
  151.         return;
  152.     }
  153.     /* Update the users liatifor persistence calculation */
  154.     upd_nusers(interface,hdr.source.call);
  155.     /* Update the MHEARD liatifor this interface */
  156.     if(interface->mheard != 0){    /* first check if we have to keep it */
  157.         updmheard(interface,1,&hdr); /* update the liat */
  158.     }
  159.     /* check source address. it must NOT appear in the exclude liat */
  160.     ASSIGN(addr,hdr.source);    /* get the source address */
  161.     addr.ssid = 0;            /* discard the SSID */
  162.     if((axc = find_axcall(ax25_excl,&addr)) != NULLAXCALL &&
  163.         ((axc->flags & MULTI_IF) || axc->interface == interface)) {
  164.         free_p(bp);
  165.         return;
  166.     }
  167.     timerscale = hdr.ndigis + 1;    /* default scaling of timer values */
  168.  
  169.     /* Scan, looking for our call in the repeater fields, if any.
  170.      * Repeat appropriate packets.
  171.      */
  172.     for(ap = &hdr.digis[0]; ap < &hdr.digis[hdr.ndigis]; ap++){
  173.         if(ap->ssid & REPEATED)
  174.         continue;    /* Already repeated */
  175.         /* Check if packet is directed to us as a digipeater */
  176.         if((axc = find_axcall(ax25_digi,ap)) != NULLAXCALL){
  177.         /* check dest address. it must NOT appear in the exclude liat */
  178.         ASSIGN(addr,hdr.dest);    /* get the dest address */
  179.         addr.ssid = 0;        /* discard the SSID */
  180.         if((axd = find_axcall(ax25_excl,&addr)) != NULLAXCALL &&
  181.             ((axd->flags & MULTI_IF) ||
  182.              axd->interface == interface || axd->interface == axc->interface)) {
  183.             free_p(bp);
  184.             return;        /* if any doubt, refuse it */
  185.         }
  186.         switch (axc->mode)    /* check the digi mode */
  187.         {
  188.         case DIGIPEAT:        /* bare digipeater */
  189.             if (axc->interface == interface){ /* this band? */
  190.             if (!digipeat)    /* in-band digi disabled? */
  191.                 break;    /* throw it away */
  192.             } else {        /* not "home", gateway request */
  193.             if (axc->flags & DIGIGATEWAY &&
  194.                 (axd = find_axcall(ax25_digi,interface->hwaddr))
  195.                 != NULLAXCALL &&
  196.                  axd->mode == DIGIPEAT &&
  197.                  axd->flags & DIGIGATEWAY){
  198.                  /* swap callsign and interface */
  199.                  ASSIGN(*ap,*((struct ax25_addr *) interface->hwaddr));
  200.                  interface = axc->interface;
  201.             } else {
  202.                 break;    /* gateway conditions not fulfilled... */
  203.             }
  204.             }
  205.  
  206.             /* kick it back out */
  207.             ap->ssid |= REPEATED;
  208.             if((hbp = htonax25(&hdr,bp)) != NULLBUF){
  209.             if(interface->forw != NULLIF)
  210.                 (*interface->forw->raw)(interface->forw,hbp);
  211.             else
  212.                 (*interface->raw)(interface,hbp);
  213.             tnc2_kissrcv(interface,&hdr,bp,4);
  214.             bp = NULLBUF;
  215.             }
  216.             break;
  217.  
  218.         case DIGICONNECT:    /* digipeater simulating connection */
  219.             if ((axc->flags & MULTI_IF) ||
  220.             axc->interface == interface ||
  221.             (axc->flags & DIGIGATEWAY)){
  222.             /* address is okay */
  223.             if (bp != NULLBUF){
  224.                 timerscale = (int) (ap - &hdr.digis[0]) + 1;
  225.                 goto for_us;/* handle as if addressed to us */
  226.             }
  227.             }
  228.             break;
  229.         }
  230.         }
  231.         tnc2_kissrcv(interface,&hdr,bp,4);
  232.         free_p(bp);            /* Dispose if not forwarded */
  233.         return;
  234.     }
  235.     /* Packet has passed all repeaters, now look at destination */
  236.     if((axc = find_axcall(ax25_call,&hdr.dest)) == NULLAXCALL ||
  237.         !((axc->flags & MULTI_IF) || axc->interface == interface)) {
  238.         /* Not for us, or wrong interface for this callsign */
  239.         tnc2_kissrcv(interface,&hdr,bp,3);
  240.         free_p(bp);
  241.         return;
  242.     }
  243.  
  244.     if(bp == NULLBUF){
  245.         /* Nothing left */
  246.         return;
  247.     }
  248.     /* Sneak a peek at the control field. This kludge is necessary because
  249.      * AX.25 lacks a proper protocol ID field between the address and LAPB
  250.      * sublayers; a control value of UI indicates that LAPB is to be
  251.      * bypassed.
  252.      */
  253.     if((*bp->data & ~PF) == UI && axc->mode == IP_ARP_CON){
  254.         char pid;
  255.  
  256.         tnc2_kissrcv(interface,&hdr,bp,2);
  257.         (void) pullchar(&bp);
  258.         if(pullup(&bp,&pid,1) != 1)
  259.             return;        /* No PID */
  260.         /* Handle packets. Multi-frame messages are not allowed */
  261.         switch(pid & (PID_FIRST | PID_LAST | PID_PID))
  262.         {
  263.         case (PID_IP | PID_FIRST | PID_LAST):
  264.             if(!(axc->flags & MULTICAST) || axc->flags & IP_ARP_MULTI){
  265.                 ip_route(bp,axc->flags & MULTICAST);
  266.                 return;
  267.             }
  268.         case (PID_ARP | PID_FIRST | PID_LAST):
  269.             if(!(axc->flags & MULTICAST) || axc->flags & IP_ARP_MULTI){
  270.                 arp_input(interface,bp);
  271.                 return;
  272.             }
  273.         case (PID_NETROM | PID_FIRST | PID_LAST):
  274.             /* NET/ROM is very poorly layered. The meaning of the stuff
  275.              * following the PID of CF depends on what's in the AX.25 dest
  276.              * field.
  277.              */
  278.             if(axc->flags & NETROM_MULTI && hdr.ndigis == 0){
  279.                 nr_nodercv(interface,&hdr.source,bp);
  280.                 return;
  281.             }
  282.             break;
  283.         }
  284.         free_p(bp);
  285.         return;
  286.     }
  287.  
  288.     if(axc->flags & MULTICAST){    /* don't allow connects to broadcast */
  289.         tnc2_kissrcv(interface,&hdr,bp,2);
  290.         free_p(bp);
  291.         return;
  292.     }
  293.  
  294. for_us: if (axc->port == TNC2PORT &&
  295.         (axc->mode == CONNECT || axc->mode == DIGICONNECT) &&
  296.         tnc2_kissrcv(interface,&hdr,bp,1)) {
  297.         free_p(bp);
  298.         return;
  299.     }
  300.  
  301.     tnc2_kissrcv(interface,&hdr,bp,2);
  302.  
  303.     setdigi = 0;            /* no need to set digi path (yet) */
  304.     /* Find the source/dest address pair in hash table */
  305.     if((axp = find_ax25(&hdr.source,&hdr.dest)) == NULLAX25){
  306.         /* He is new! First check for reasonable callsign */
  307.         if(valid_addr(&hdr.source) != 0) {
  308.             free_p(bp);
  309.             return;
  310.         }
  311.         /* Create a new ax25 entry for this guy,
  312.          * insert into hash table keyed on his address,
  313.          * and initialize table entries
  314.          */
  315.         if((axp = cr_ax25(&hdr.source,&hdr.dest)) == NULLAX25){
  316.             free_p(bp);
  317.             return;
  318.         }
  319.         /* Swap source and destination callsigns */
  320.         ASSIGN(axp->addr.dest,hdr.source);
  321.         ASSIGN(axp->addr.source,hdr.dest);
  322.         setdigi++;        /* also set the digi string and interface */
  323.  
  324.         /* see if it is a connection to an ax25 port */
  325.         if (axc->port != 0 &&    /* a port ? */
  326.             (axc->mode == CONNECT || axc->mode == DIGICONNECT)){
  327.             axp->r_upcall = axc->r_upcall;    /* set upcall handlers */
  328.             axp->t_upcall = axc->t_upcall;
  329.             axp->s_upcall = axc->s_upcall;
  330.             axp->user = (char *) axc;    /* link to ax call */
  331.         }
  332.     }
  333.  
  334.     /* set digi path for new connections, but always set it when the
  335.      * received frame is an SABM.  This allows other stations to
  336.      * reconnect to us with a different digi path (TNC2 reconnect cmd).
  337.      * same holds for the interface the connection is on.
  338.      */
  339.     if(setdigi || ((*bp->data & ~PF) == SABM)){
  340.         if(hdr.ndigis > 0){
  341.             int i,j;
  342.  
  343.             /* Construct reverse digipeater path */
  344.             for(i=hdr.ndigis-1,j=0;i >= 0;i--,j++){
  345.                 ASSIGN(axp->addr.digis[j],hdr.digis[i]);
  346.                 axp->addr.digis[j].ssid ^= REPEATED;
  347.                 axp->addr.digis[j].ssid &= ~E;
  348.             }
  349.         }
  350.         /* Scale timers to account for extra delay */
  351.         axp->t1.start = t1init * timerscale;
  352.         axp->t2.start = t2init * timerscale;
  353.         /*axp->t3.start = t3init * timerscale;
  354.         axp->t4.start = t4init * timerscale;*/
  355.         axp->addr.ndigis = hdr.ndigis;
  356.  
  357.         axp->interface = interface;
  358.     }
  359.  
  360.     if(hdr.cmdrsp == UNKNOWN)
  361.         axp->proto = V1;    /* Old protocol in use */
  362.     else
  363.         axp->proto = V2;
  364.  
  365.     lapb_input(axp,hdr.cmdrsp,bp);
  366. }
  367.  
  368. /* General purpose AX.25 frame output */
  369. int
  370. sendframe(axp,cmdrsp,ctl,data)
  371. struct ax25_cb *axp;
  372. char cmdrsp;
  373. char ctl;
  374. struct mbuf *data;
  375. {
  376.     struct mbuf *hbp,*cbp,*ibp,*htonax25();
  377.     struct ax25_call *axc;
  378.     int rv,i;
  379.  
  380.     if(axp == NULLAX25 || axp->interface == NULLIF)
  381.         return -1;
  382.  
  383.     /* Add control field */
  384.     if((cbp = pushdown(data,1)) == NULLBUF){
  385.         free_p(data);
  386.         return -1;
  387.     }
  388.     cbp->data[0] = ctl;
  389.  
  390.     axp->addr.cmdrsp = cmdrsp;
  391.     /* Create address header */
  392.     if((hbp = htonax25(&axp->addr,cbp)) == NULLBUF){
  393.         free_p(cbp);
  394.         return -1;
  395.     }
  396.  
  397.     /* First make a check to see if it's directed to ourselves */
  398.     for(i = 0; i < axp->addr.ndigis; i++)
  399.         if(!(axp->addr.digis[i].ssid & REPEATED))
  400.         break;
  401.     if((i == axp->addr.ndigis &&
  402.         (axc = find_axcall(ax25_call,&axp->addr.dest)) != NULLAXCALL) ||
  403.        (i < axp->addr.ndigis &&
  404.         (axc = find_axcall(ax25_digi,&axp->addr.digis[i])) != NULLAXCALL) &&
  405.        !(axc->flags & MULTICAST) &&
  406.        ((axc->flags & (MULTI_IF|DIGIGATEWAY)) || axc->interface == axp->interface)) {
  407.         /* put it on the ax loopback queue with interface ptr */
  408.         if((ibp = alloc_mbuf(4 + len_mbuf(hbp))) == NULLBUF){
  409.             free_p(hbp);
  410.             return -1;
  411.         }
  412.         put32(ibp->data,(long) axp->interface);
  413.         ibp->cnt = 4 + pullup(&hbp,ibp->data + 4,len_mbuf(hbp));
  414.         enqueue(&axloopq,ibp);
  415.         rv = 0;
  416.     } else {
  417.         /* Not for us, really ship it */
  418.         if(axp->interface->forw != NULLIF)
  419.             rv = (*axp->interface->forw->raw)(axp->interface->forw,hbp);
  420.         else
  421.             rv = (*axp->interface->raw)(axp->interface,hbp);
  422.     }
  423.  
  424.     if(cmdrsp == COMMAND)
  425.         start_timer(&axp->t1);
  426.  
  427.     return rv;
  428. }
  429. /* AX.25 UI frame output for beacons etc */
  430. int
  431. senduiframe(ifp,addr,data)
  432. struct interface *ifp;
  433. struct ax25 *addr;
  434. struct mbuf *data;
  435. {
  436.     struct mbuf *hbp,*cbp,*htonax25();
  437.  
  438.     if(ifp == NULLIF)
  439.         return -1;
  440.  
  441.     /* Add control field (UI) */
  442.     if((cbp = pushdown(data,1)) == NULLBUF){
  443.         free_p(data);
  444.         return -1;
  445.     }
  446.     cbp->data[0] = UI;
  447.  
  448.     addr->cmdrsp = UNKNOWN;
  449.     /* Create address header */
  450.     if((hbp = htonax25(addr,cbp)) == NULLBUF){
  451.         free_p(cbp);
  452.         return -1;
  453.     }
  454.  
  455.     /* Ship it */
  456.     if(ifp->forw != NULLIF)
  457.         return (*ifp->forw->raw)(ifp->forw,hbp);
  458.     else
  459.         return (*ifp->raw)(ifp,hbp);
  460. }
  461. /* Initialize AX.25 entry in arp device table. also puts it in call table */
  462. axarp()
  463. {
  464.     int psax25(),setpath();
  465.     struct ax25_call *axc;
  466.     struct ax25_addr ax25_bdcst;
  467.  
  468.     setcall(&ax25_bdcst,"QST-0");
  469.     if ((axc = cr_axcall(ax25_call,&ax25_bdcst)) != NULLAXCALL){
  470.         axc->mode  = IP_ARP_CON;
  471.         axc->flags = MULTI_IF | MULTICAST | IP_ARP_MULTI;
  472.     }
  473.  
  474.     memcpy(axbdcst,ax25_bdcst.call,ALEN);
  475.     axbdcst[ALEN] = ax25_bdcst.ssid;
  476.  
  477.     arp_init(ARP_AX25,AXALEN,PID_FIRST|PID_LAST|PID_IP,
  478.      PID_FIRST|PID_LAST|PID_ARP,axbdcst,psax25,setpath);
  479. }
  480.